package com.example.basic.web.service.notice.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.basic.base.impl.BaseEntityServiceImpl;
import com.example.basic.exception.ServiceException;
import com.example.basic.utils.IdUtils;
import com.example.basic.utils.StringUtils;
import com.example.basic.web.enums.*;
import com.example.basic.web.mapper.notice.InNoticeMapper;
import com.example.basic.web.model.binding.BindingInfo;
import com.example.basic.web.model.device.Device;
import com.example.basic.web.model.notice.InNotice;
import com.example.basic.web.model.pharmIn.PharmInRecord;
import com.example.basic.web.model.remains.RemainsInfo;
import com.example.basic.web.model.terminal.TerminalRecord;
import com.example.basic.web.model.zoneDepot.ZoneDepot;
import com.example.basic.web.response.InNoticeResponse;
import com.example.basic.web.response.PdaNoticeResponse;
import com.example.basic.web.service.binding.BindingInfoService;
import com.example.basic.web.service.common.CommonService;
import com.example.basic.web.service.dataCode.DataCodeService;
import com.example.basic.web.service.device.DeviceService;
import com.example.basic.web.service.notice.InNoticeService;
import com.example.basic.web.service.pharmIn.PharmInRecordService;
import com.example.basic.web.service.remains.RemainsInfoService;
import com.example.basic.web.service.terminal.TerminalRecordService;
import com.example.basic.web.service.transTask.TransTaskService;
import com.example.basic.web.service.zoneDepot.ZoneDepotService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

import static com.example.basic.utils.CheckUtil.notNull;


@Service
public class InNoticeServiceImpl extends BaseEntityServiceImpl<InNoticeMapper, InNotice> implements InNoticeService {

    @Resource
    private InNoticeMapper inNoticeMapper;

    @Resource
    private DataCodeService dataCodeService;

    @Resource
    private CommonService commonService;

    @Resource
    private HttpServletRequest request;

    @Resource
    private PharmInRecordService pharmInRecordService;

    @Resource
    private RemainsInfoService remainsInfoService;

    @Resource
    private TerminalRecordService terminalRecordService;

    @Resource
    private BindingInfoService bindingInfoService;

    @Resource
    private DeviceService deviceService;

    @Resource
    private ZoneDepotService zoneDepotService;

    @Resource
    private TransTaskService transTaskService;

    /**
     * 批量新增
     * @param inNoticeList
     * @return
     */
    @Override
    public Boolean batchAdd(List<InNotice> inNoticeList,Boolean isAudit) {
        notNull(inNoticeList,"入库通知单模型不能为空");

        //参数校验
        inNoticeList.forEach(inNotice -> {
            checkParams(inNotice);
        });

        //遗体编码列表
        List<String> remainsCodeList = inNoticeList.stream().map(InNotice::getRemainsCode).collect(Collectors.toList());

        //判断遗体是否已入库
        LambdaQueryWrapper<InNotice> lqw = new LambdaQueryWrapper<>();
        lqw.in(InNotice::getRemainsCode,remainsCodeList);
        List<InNotice> local = this.mapper.selectList(lqw);

        if(local.size() > 0){
            throw new ServiceException("遗体已存在入库通知单");
        }

        //更新库位为占用
        List<String> depotList = inNoticeList.stream().map(InNotice::getDepotCode).collect(Collectors.toList());
        if(depotList.size() > 0 ){
            zoneDepotService.useDepot(depotList,YesNoEnum.YES_FLAG.getType());
        }

        //生成入库通知单编码
        List<String> inNoticeCode = dataCodeService.generateDataCodeNoList(DataCodeEnum.IN_NOTICE_CODE.getType(),inNoticeList.size());

        for (int i = 0; i < inNoticeList.size(); i++) {
            inNoticeList.get(i).setInNoticeCode(inNoticeCode.get(i));
            preCreate(inNoticeList.get(i));
            inNoticeList.get(i).setId(IdUtils.fastUUID());
            inNoticeList.get(i).setStatus(AuditEnum.ADD.getType());
        }

        saveBatch(inNoticeList);

        List<BindingInfo> bindingInfos = new ArrayList<>();
        //根据入库通知单添加绑定关系
        inNoticeList.forEach(inNotice -> {
            BindingInfo bindingInfo = new BindingInfo();
            bindingInfo.setDeviceCode(inNotice.getDockStation());
            bindingInfo.setRemainsCode(inNotice.getRemainsCode());
            bindingInfo.setDocumentNo(inNotice.getInNoticeCode());

            bindingInfos.add(bindingInfo);
        });
        if(bindingInfos.size() > 0){
            bindingInfoService.batchAdd(bindingInfos);
        }

        if(isAudit){
            this.auditOrCancel(inNoticeList.get(0));
        }

        return true;
    }

    /**
     * 保存或者修改
     * @param inNotice 模型
     * @return
     */
    @Override
    public InNotice modify(InNotice inNotice) {

        //参数校验
        checkParams(inNotice);
        notNull(inNotice.getInNoticeCode(), "通知单编码不能为空");

        InNotice localNotice = this.detail(inNotice.getInNoticeCode());
        if(localNotice.getStatus().equals(AuditEnum.AUDIT.getType())){
            throw new ServiceException("已审核的通知单不允许修改");
        }

        inNotice.setId(localNotice.getId());
        preUpdate(inNotice);

        this.save(inNotice);
        return detail(inNotice.getInNoticeCode());
    }

    /**
     * 参数校验
     * @param inNotice
     */
    private void checkParams(InNotice inNotice) {
        notNull(inNotice,"实体不能为空");
        notNull(inNotice.getRemainsCode(),"遗体编码不能为空");
//        notNull(inNotice.getPharmCode(),"仓库编码不能为空");
//        notNull(inNotice.getZoneCode(),"分区编码不能为空");
//        notNull(inNotice.getDepotCode(),"库位编码不能为空");
    }

    /**
     * 详情
     * @param inNoticeCode 入库通知单编码
     * @return
     */
    @Override
    public InNotice detail(String inNoticeCode) {
        notNull(inNoticeCode, "入库通知单编码不能为空");

        return  this.mapper.detail(inNoticeCode);
    }

    /**
     * 删除
     * @param inNoticeCode 入库通知单编码
     * @return
     */
    @Override
    public int delete(String inNoticeCode) {
        notNull(inNoticeCode,"入库通知单编码不能为空");

        InNotice inNotice = detail(inNoticeCode);
        if(inNotice == null){
            throw new ServiceException("未查询到当前数据");
        }

        if(inNotice.getStatus().equals(AuditEnum.AUDIT.getType())){
            throw new ServiceException("已审核的通知单无法删除");
        }

        //删除绑定关系
        bindingInfoService.cancel(inNotice.getRemainsCode());

        return this.mapper.deleteById(inNotice.getId());
    }

    /**
     * 审核/取消审核  zzl
     * @param inNotice 入库通知单
     * @return
     */
    @Override
    public int auditOrCancel(InNotice inNotice){
        notNull(inNotice,"入库通知单不能为空");
        notNull(inNotice.getInNoticeCode(),"入库通知单编码不能为空");

        InNotice localNotice = detail(inNotice.getInNoticeCode());

        if(localNotice == null){
            throw new ServiceException("未查询到当前数据");
        }

        //审核
        localNotice.setStatus(AuditEnum.AUDIT.getType());
        localNotice.setAuditTime(commonService.getDataBaseTime());
        localNotice.setAuditPerson((String) request.getAttribute("userCode"));
        localNotice.setDockStation(inNotice.getDockStation());
        localNotice.setRemainsCode(inNotice.getRemainsCode());
        localNotice.setPharmCode(inNotice.getPharmCode());


        localNotice.setZoneCode(inNotice.getZoneCode());
        localNotice.setDepotCode(inNotice.getDepotCode());
        localNotice.setAdmireHall(inNotice.getAdmireHall());
        localNotice.setCremationRoom(inNotice.getCremationRoom());

        //审核通过，生成入库单
        PharmInRecord pharmInRecord = new PharmInRecord();
        pharmInRecord.setInNoticeCode(inNotice.getInNoticeCode());
        pharmInRecord.setStatus(InParamStatusEnum.WAIT.getType());
        pharmInRecordService.add(pharmInRecord);

        //担架板不为空，根据遗体编码获取绑定关系
        BindingInfo bindingInfo = bindingInfoService.detail(inNotice.getRemainsCode());
        //绑定关系为空，维护绑定关系
        if (bindingInfo != null) {
            //绑定关系不为空，更新绑定关系为入库单
            bindingInfo.setDocumentNo(pharmInRecord.getInPharmCode());
            bindingInfoService.modify(bindingInfo);
        }

        Device device = deviceService.detail(localNotice.getDockStation());
        if (device.getStatus().equals(DeviceStatusEnum.standby.getType())) {
            //更新接驳台为占用
            deviceService.freeOrUse(localNotice.getDockStation());
        }
        //库位不为空，更新库位为占用
        if (StringUtils.notEmptyParams(inNotice.getDepotCode())) {
            zoneDepotService.useDepot(Arrays.asList(inNotice.getDepotCode()), YesNoEnum.YES_FLAG.getType());
        }
        //获取遗体信息
        RemainsInfo remainsInfo = remainsInfoService.detail(localNotice.getRemainsCode());

        //创建作业任务
        // 择期火化--入库流程
        if (remainsInfo.getCremationType().equals("2")) {
            //任务流程  接驳台->库位
            this.inPharmStruct(localNotice, remainsInfo,pharmInRecord.getInPharmCode());
        } else {
            //任务流程 接驳台->特殊处理->瞻仰->火化
            this.cremationStruct(localNotice, remainsInfo, pharmInRecord.getInPharmCode());
        }

        preUpdate(localNotice);
        this.mapper.updateById(localNotice);

        //任务开始
//        try {
//            transTaskService.sendTransTask(pharmInRecord.getInPharmCode());
//        } catch (IOException e) {
//            throw new RuntimeException(e);
//        }

        pharmInRecordService.modifyStatus(pharmInRecord.getInPharmCode());

        return 1;
    }

    /**
     * 任务流程 接驳台->运送车->转运接驳台->可升降转运车->特殊处理->瞻仰->火化->结束返回
     * @param inNotice
     * @param remainsInfo
     */
    private void cremationStruct(InNotice inNotice,RemainsInfo remainsInfo,String documentNo) {
        List<TerminalRecord> terminalRecordList = new ArrayList<>();

        //直接火化
        TerminalRecord terminalRecord = new TerminalRecord();

        //初始点位
        Device device = deviceService.detail(inNotice.getDockStation());

        //开始点位
        String beginAddress = device.getDevicePoint();

        Integer sortNo = 1;

        //结束点位
        String endAddress = DeviceAddressEnum.STAGING_AREA.getType();

        terminalRecord.setOperType("入口暂存区");
        terminalRecord.setRemainsCode(inNotice.getRemainsCode());
        terminalRecord.setInstructStart(beginAddress);
        terminalRecord.setInstructEnd(endAddress);
        terminalRecord.setStatus("0");
        terminalRecord.setSortNo(sortNo);
        terminalRecord.setDocumentNo(documentNo);
        terminalRecord.setInstructAddress(endAddress);
        terminalRecordList.add(terminalRecord);

        beginAddress = DeviceAddressEnum.STAGING_AREA.getType();
        sortNo += 1;


        //是否需要特殊处理
        if (StringUtils.notEmptyParams(remainsInfo.getSpecialHandle())) {
            String[] split = remainsInfo.getSpecialHandle().split(",");

//            Map map = new HashMap();
            for (int i = 0; i < split.length; i++) {

                //单据状态
                String documnentStatus = "";
                String operType = null;
                if (split[i].equals("1")) {
                    documnentStatus = "4";
                    //整容,化妆
                    endAddress = DeviceAddressEnum.MAKEUP.getType();
                    operType = DeviceAddressEnum.MAKEUP.getDesc();
                } else if (split[i].equals("2")) {
                    documnentStatus = "2";
                    //消毒
                    endAddress = DeviceAddressEnum.DISINFECT.getType();
                    operType = DeviceAddressEnum.DISINFECT.getDesc();
                } else if (split[i].equals("4")) {
//                    if(map.containsKey("3") || map.containsKey("4")){
//                        continue;
//                    }
                    documnentStatus = "3";
                    //spa
                    endAddress = DeviceAddressEnum.SPA.getType();
                    operType = DeviceAddressEnum.SPA.getDesc();
                }else {continue;}

                terminalRecord = new TerminalRecord();
                terminalRecord.setOperType(operType);
                terminalRecord.setRemainsCode(inNotice.getRemainsCode());
                terminalRecord.setInstructStart(beginAddress);
                terminalRecord.setInstructEnd(endAddress);
                terminalRecord.setStatus("0");
                terminalRecord.setSortNo(sortNo);
                terminalRecord.setDocumentNo(documentNo);
                terminalRecord.setDocumentStatus(documnentStatus);
                terminalRecord.setInstructAddress(endAddress);
                terminalRecordList.add(terminalRecord);
                sortNo+=1;
                beginAddress = endAddress;
//                map.put(split[i], split[i]);
                if(i == split.length - 1){
                    break;
                }
            }
        }

        //是否需要瞻仰
        if(!"3".equals(remainsInfo.getAdmire())){

            //暂存区消息确认
            terminalRecord = new TerminalRecord();
            terminalRecord.setOperType("瞻仰暂存区");
            terminalRecord.setRemainsCode(inNotice.getRemainsCode());
            terminalRecord.setInstructStart(beginAddress);
            terminalRecord.setInstructEnd(DeviceAddressEnum.STAGING_AREA.getType());
            terminalRecord.setStatus("0");
            terminalRecord.setSortNo(sortNo);
            terminalRecord.setDocumentNo(documentNo);
            terminalRecord.setInstructAddress(DeviceAddressEnum.STAGING_AREA.getType());
            terminalRecordList.add(terminalRecord);

            beginAddress = DeviceAddressEnum.STAGING_AREA.getType();
            sortNo += 1;

            terminalRecord = new TerminalRecord();
            terminalRecord.setOperType("瞻仰厅提升");
            terminalRecord.setRemainsCode(inNotice.getRemainsCode());
            terminalRecord.setInstructStart(beginAddress);
            terminalRecord.setInstructEnd(DeviceAddressEnum.ADMIRE.getType());
            terminalRecord.setStatus("0");
            terminalRecord.setSortNo(sortNo);
            terminalRecord.setDocumentNo(documentNo);
            terminalRecord.setDocumentStatus("7");
            terminalRecord.setInstructAddress(DeviceAddressEnum.ADMIRE.getType());

            terminalRecordList.add(terminalRecord);

            beginAddress = DeviceAddressEnum.ADMIRE.getType();
            sortNo += 1;
        }

        //火化间
        //-1层提升机->提升机接驳台->火化间提升机
        terminalRecord = new TerminalRecord();
        terminalRecord.setOperType("-1层提升机");
        terminalRecord.setRemainsCode(inNotice.getRemainsCode());
        terminalRecord.setInstructStart(beginAddress);
        terminalRecord.setInstructEnd(DeviceAddressEnum.TRANS_HOIST.getType());
        terminalRecord.setStatus("0");
        terminalRecord.setSortNo(sortNo);
        terminalRecord.setDocumentNo(documentNo);
        terminalRecord.setInstructAddress(DeviceAddressEnum.TRANS_HOIST.getType());
        terminalRecordList.add(terminalRecord);
        sortNo += 1;
        beginAddress = DeviceAddressEnum.TRANS_HOIST.getType();

        terminalRecord = new TerminalRecord();
        terminalRecord.setOperType("火化间提升机");
        terminalRecord.setRemainsCode(inNotice.getRemainsCode());
        terminalRecord.setInstructStart(beginAddress);
        terminalRecord.setInstructEnd(DeviceAddressEnum.CREMATION.getType());
        terminalRecord.setStatus("0");
        terminalRecord.setSortNo(sortNo);
        terminalRecord.setDocumentNo(documentNo);
        terminalRecord.setInstructAddress(DeviceAddressEnum.CREMATION.getType());
        terminalRecordList.add(terminalRecord);

        terminalRecordService.batchAdd(terminalRecordList);

    }

    /**
     * 任务流程  接驳台->运送车->转运接驳台->可升降转运车->库位->结束返回
     * @param inNotice
     */
    private void inPharmStruct(InNotice inNotice,RemainsInfo remainsInfo,String documentNo){

        Device detail = deviceService.detail(inNotice.getDockStation());

        List<TerminalRecord> terminalRecordList = new ArrayList<>();

        //开始点位
        String beginAddress = detail.getDevicePoint();

        Integer sortNo = 1;

        //结束点位
        String endAddress = DeviceAddressEnum.STAGING_AREA.getType();

        TerminalRecord terminalRecord = new TerminalRecord();

        terminalRecord.setOperType("入口暂存区");
        terminalRecord.setRemainsCode(inNotice.getRemainsCode());
        terminalRecord.setInstructStart(beginAddress);
        terminalRecord.setInstructEnd(endAddress);
        terminalRecord.setStatus("0");
        terminalRecord.setSortNo(sortNo);
        terminalRecord.setDocumentNo(documentNo);
        terminalRecord.setInstructAddress(endAddress);
        terminalRecordList.add(terminalRecord);

        beginAddress = DeviceAddressEnum.STAGING_AREA.getType();
        sortNo += 1;

        //是否需要特殊处理
        if (StringUtils.notEmptyParams(remainsInfo.getSpecialHandle())) {
            String[] split = remainsInfo.getSpecialHandle().split(",");
            for (int i = 0; i < split.length; i++) {


                //单据状态
                String documnentStatus = "";
                String operType = "";
               if (split[i].equals("2")) {
                    documnentStatus = "2";
                    //消毒
                    endAddress = DeviceAddressEnum.DISINFECT.getType();
                   operType = DeviceAddressEnum.DISINFECT.getDesc();
                } else if (split[i].equals("4")) {
                    documnentStatus = "3";
                    //spa
                    endAddress = DeviceAddressEnum.SPA.getType();
                   operType = DeviceAddressEnum.SPA.getDesc();
                }else {
                   continue;
               }

                terminalRecord = new TerminalRecord();
                terminalRecord.setOperType("operType");
                terminalRecord.setRemainsCode(inNotice.getRemainsCode());
                terminalRecord.setInstructStart(beginAddress);
                terminalRecord.setInstructEnd(endAddress);
                terminalRecord.setStatus("0");
                terminalRecord.setSortNo(sortNo);
                terminalRecord.setDocumentNo(documentNo);
                terminalRecord.setDocumentStatus(documnentStatus);
                terminalRecord.setInstructAddress(endAddress);
                terminalRecordList.add(terminalRecord);
                sortNo+=1;
                beginAddress = endAddress;
                if(i == split.length - 1){
                    break;
                }
            }
        }

        //获取库位信息
        ZoneDepot zoneDepot = zoneDepotService.detail(inNotice.getDepotCode());
        //接驳台->库位
        terminalRecord = new TerminalRecord();
        terminalRecord.setOperType("运送遗体");
        terminalRecord.setTerminalCode(inNotice.getDockStation());
        terminalRecord.setRemainsCode(inNotice.getRemainsCode());
        terminalRecord.setInstructTime(commonService.getDataBaseTime());
        terminalRecord.setInstructStart(beginAddress);
        terminalRecord.setInstructEnd(zoneDepot.getDepotPoint());
        terminalRecord.setDepotCode(inNotice.getDepotCode());
        terminalRecord.setStatus("0");
        terminalRecord.setOperPerson((String) request.getAttribute("userCode"));
        terminalRecord.setSortNo(1);
        terminalRecord.setDocumentNo(documentNo);
        terminalRecord.setTaskRecordId(IdUtils.fastUUID());
        terminalRecordList.add(terminalRecord);

        terminalRecordService.batchAdd(terminalRecordList);
    }

    /**
     * 入库通知单列表
     * @param queryPage 分页
     * @param searchParam 遗体名称，拼音码，五笔码
     * @param sex 性别
     * @param pharmCode 库房编码
     * @param zoneCode 分区编码
     * @param depotCode 库位编码
     * @param beginTime 开始日期
     * @param endTime 结束日期
     * @return
     */
    @Override
    public IPage<InNoticeResponse> queryList(Page<InNoticeResponse> queryPage, String searchParam, String sex, String pharmCode, String zoneCode, String depotCode, String beginTime, String endTime) {

        return this.mapper.queryList(queryPage,searchParam,sex,pharmCode,zoneCode,depotCode,beginTime,endTime);
    }

    /**
     * 入库通知单列表
     *
     * @param queryPage
     * @param searchParam 模糊搜索(遗体名称，拼音码，五笔码)
     * @param type        类型，1-待发起，2-已发起
     * @return
     */
    @Override
    public IPage<PdaNoticeResponse> noticeList(Page<PdaNoticeResponse> queryPage, String searchParam, String type) {
        return this.mapper.noticeList(queryPage,searchParam,type);
    }

    /**
     * 通过遗体编码获取入库通知单
     * @param remainsCode 遗体编码
     * @return
     */
    @Override
    public InNotice findByRemainsCode(String remainsCode) {
        notNull(remainsCode,"遗体编码不能为空");

        LambdaQueryWrapper<InNotice> lqw = new LambdaQueryWrapper<>();
        lqw.eq(InNotice::getRemainsCode,remainsCode);
        return this.mapper.selectOne(lqw);
    }

    /**
     * PDA-入库上架
     * @param inNotice
     * @return
     */
    @Override
    public Boolean inPharm(InNotice inNotice) {

        if (StringUtils.emptyParams(inNotice.getInNoticeCode())) {
            this.batchAdd(Collections.singletonList(inNotice),true);
        }else {
            this.auditOrCancel(inNotice);
        }

        return true;
    }

}
